package com.umeox.watch.moto.dataservice.observer;

import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.AsyncTask;
import android.os.Build;
import android.os.SystemClock;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.util.Log;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.umeox.moto.common.log.Logger;
import com.umeox.moto.common.utils.DateUtils;
import com.umeox.moto.mqtt.base.AError;
import com.umeox.moto.mqtt.base.ARequest;
import com.umeox.moto.mqtt.base.AResponse;
import com.umeox.watch.location.proto.LocationProto;
import com.umeox.watch.moto.dataservice.DataProvider;
import com.umeox.watch.moto.dataservice.base.BaseApp;
import com.umeox.watch.moto.dataservice.base.LauncherManager;
import com.umeox.watch.moto.dataservice.constants.MqttConstants;
import com.umeox.watch.moto.dataservice.db.AppDataBase;
import com.umeox.watch.moto.dataservice.db.model.LocationInfo;
import com.umeox.watch.moto.dataservice.mqtt.bean.eventbean.BaseLocation;
import com.umeox.watch.moto.dataservice.mqtt.impl.MqttServiceDelegate;
import com.umeox.watch.moto.dataservice.mqtt.interfaces.IPublishListener;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

public class FalloffObserver implements SensorEventListener {
    private static final String TAG = "FalloffObserver";
    private final int STATE_ON = 0, STATE_OFF = 5;
    private final SensorManager sensorManager;
    private boolean sensorRegisted;
    private FallOffAlarmTask alarmTask;
    private static boolean sVibratored;
    private long mRealtime;
    private static final long FREQUENCY_TIME = TimeUnit.MINUTES.toMillis(5);

    private FalloffObserver() {
        sensorManager = (SensorManager) BaseApp.getInstance().getSystemService(Context.SENSOR_SERVICE);

    }

    public static FalloffObserver getInstance() {
        return Holder.INSTANCE;
    }

    public void registerSensor() {
        Logger.i(TAG, "register proximity sensor listener");
        int sensorSize = sensorManager.getSensorList(Sensor.TYPE_PROXIMITY).size();
        Logger.i(TAG, "proximity sensors: " + sensorSize);
        if (sensorSize < 1) {
            return;
        }
        Sensor proximitySensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
        Logger.i(TAG, "default: " + proximitySensor.getName() + " sensorRegisted:" + sensorRegisted);
        if (sensorRegisted) {
            unRegisterSensor();
        }
        sensorRegisted = sensorManager.registerListener(this, proximitySensor, (int) TimeUnit.MINUTES.toMicros(1));
        Logger.i(TAG, "register proximity sensor listener>>>" + (sensorRegisted ? "success" : "failure"));
    }

    public void unRegisterSensor() {
        Log.d(TAG, "unRegisterSensor: ");
        mRealtime = 0;
        try {
            sensorRegisted = false;
            if (sensorManager != null) {
                sensorManager.unregisterListener(this);
            }
        } catch (Exception e) {
            Log.e(TAG, "unRegisterSensor: ", e);
        }
    }


    @Override
    public void onSensorChanged(SensorEvent event) {
        int temp = (int) event.values[0];
        Log.d(TAG, "onSensorChanged: " + temp);
        if (temp == STATE_OFF) {
            //五分钟之内不重复上报，取当前时间跟上一次上报时间对比，大于5分钟则上报
            if (((SystemClock.elapsedRealtime() - mRealtime)) > FREQUENCY_TIME) {
                if (alarmTask != null && alarmTask.getStatus() == AsyncTask.Status.RUNNING) {
                    Logger.d(TAG, "正在上报脱落报警");
                    return;
                }
                Logger.d(TAG, "触发脱落报警");
                alarmTask = new FallOffAlarmTask();
                alarmTask.execute();
            }
        }
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
        Logger.i(TAG, sensor.getName() + " accuracy changed: " + accuracy);
    }

    private static class Holder {
        private static final FalloffObserver INSTANCE = new FalloffObserver();
    }

    private static class FallOffAlarmTask extends AsyncTask<Void, Void, Boolean> {
        private final Vibrator vibrator;


        FallOffAlarmTask() {
            vibrator = (Vibrator) BaseApp.getInstance().getSystemService(Context.VIBRATOR_SERVICE);
        }

        @Override
        protected void onPreExecute() {
            //避免断网时一直震动
            if (!sVibratored) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                    vibrator.vibrate(VibrationEffect.createOneShot(200, VibrationEffect.DEFAULT_AMPLITUDE));
                } else {
                    vibrator.vibrate(200);
                }
                sVibratored = true;
            }

        }

        @Override
        protected Boolean doInBackground(Void... voids) {

            LocationProto.LocationDetail locBuilder = LocationProto.LocationDetail.newBuilder()
                    .setStartTime(System.currentTimeMillis())
                    .setEndTime(System.currentTimeMillis())
                    .setLocReason(LocationProto.LocReason.DEVICE_OFF_ALARM)
                    .setLocMode(LocationProto.LocMode.GPS)
                    .setLat(-999)
                    .setLng(-999).build();

            final AtomicBoolean result = new AtomicBoolean(false);
            CountDownLatch downLatch = new CountDownLatch(1);

            List<BaseLocation.LocationBean> locationBeanList = new ArrayList<>();
            BaseLocation.LocationBean locationBean = convert2LocationDTO(locBuilder);
            locationBeanList.add(locationBean);

            BaseLocation baseLocation = new BaseLocation();
            baseLocation.eventId = UUID.randomUUID().toString();
            baseLocation.holderId = DataProvider.getHolderId();
            baseLocation.location = locationBeanList;
            Object data = JSONObject.toJSON(baseLocation);

            if (data != null) {
                MqttServiceDelegate.sendEvent(MqttConstants.Event.NW, data, new IPublishListener() {
                    @Override
                    public void onSuccess(ARequest request, AResponse response) {
                        Logger.d(TAG, "onSuccess response:" + response.data.toString());
                        JSONObject jsonObject = JSONObject.parseObject(response.data.toString());
                        int errCode = jsonObject.getIntValue("ERR_CODE");
                        if (errCode == 0) {
                            result.set(true);
                            downLatch.countDown();
                        }
                    }

                    @Override
                    public void onFailure(ARequest request, Object message, AError error) {
                        Log.e(TAG, "onFailure: " + error.toString());
                    }
                });
            }
            if (downLatch.getCount() > 0) {
                try {
                    downLatch.await(15, TimeUnit.SECONDS);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            if (result.get()) {
                FalloffObserver.getInstance().mRealtime = SystemClock.elapsedRealtime();
                try {
                    LocationInfo params = LocationInfo.mergeFromProto(locBuilder);
                    AppDataBase.getInstance().locationInfoDao().save(params);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            return result.get();
        }

    }


    private static BaseLocation.LocationBean convert2LocationDTO(LocationProto.LocationDetail detail) {
        BaseLocation.LocationBean dto;
        dto = new BaseLocation.LocationBean();
        dto.startTime = DateUtils.formatDateTime(detail.getStartTime(), "yyyyMMdd'T'HHmmssZ");
        dto.endTime = DateUtils.formatDateTime(detail.getEndTime(), "yyyyMMdd'T'HHmmssZ");
        dto.mode = detail.getLocModeValue();
        dto.order = detail.getOrder();
        dto.lat = detail.getLat();
        dto.lng = detail.getLng();
        if (detail.getAccuracy() > 0) {
            dto.accuracy = detail.getAccuracy();
        }
        if (detail.getSpeed() > 0.0) {
            dto.speed = detail.getSpeed();
        }
        dto.battery = LauncherManager.getInstance().getBatteryLevel();
        dto.cellTower = detail.getCellTower();
        dto.nearByCellTowers = setNearByCellTowers(detail.getNearbyCellTowersList());
        dto.network = detail.getNetwork();
        dto.wifiPoints = setWifiPoints(detail.getWifiPointsList());
        dto.charge = detail.getCharge();
        return dto;
    }

    private static JSONArray setNearByCellTowers(List<String> nearByCellTowers) {
        if (nearByCellTowers != null) {
            return new JSONArray(new JSONArray(new ArrayList<>(nearByCellTowers)));
        }
        return null;
    }

    private static JSONArray setWifiPoints(List<LocationProto.WifiPoint> wifiPointList) {
        if (wifiPointList != null) {
            JSONArray jsonArray = new JSONArray(wifiPointList.size());
            for (LocationProto.WifiPoint wifiPoint : wifiPointList) {
                jsonArray.add(new JSONArray(new ArrayList<>(wifiPoint.getWifiPointList())));
            }
            Logger.e("wifiPointsJson:" + jsonArray.toJSONString());
            return jsonArray;
        }
        return null;
    }

}
